package com.iqiyi.pps.epg.core.dao.base;


//import com.iqiyi.kiwi.utils.ConvertUtils;

import com.iqiyi.kiwi.utils.ServletUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.*;

/**
 * 与具体ORM实现无关的属性过滤条件封装类, 主要记录页面中简单的搜索过滤条件.
 */
public class PropertyFilter {

//    public static void main(String[] args) {
//        PropertyFilter filter = new PropertyFilter("EQL_id_OR_fatherId", "1,2,3");
//           System.out.println(filter.getMatchValue());
//        List<PropertyFilter> list = new ArrayList<PropertyFilter>();
//        list.add(filter);
//        String builderStr = TransUtil.buildQueryStringByPropertyFilter("from Table ", list);
//        System.out.println(builderStr);
//    }

    /**
     * 多个属性间OR关系的分隔符.
     */
    public static final String OR_SEPARATOR = "_OR_";

    /**
     * 属性比较类型.
     */
    public enum MatchType {
        EQ, LIKE, ENDLIKE, STARTLIKE, EXACTLIKE, LT, GT, LE, GE, NEQ, IN;
    }

    /**
     * 属性数据类型.
     */
    public enum PropertyType {
        S(String.class), I(Integer.class), L(Long.class), N(Double.class), D(Date.class), B(Boolean.class), T(Timestamp.class), F(Float.class), Y(Byte.class);

        private Class<?> clazz;

        private PropertyType(Class<?> clazz) {
            this.clazz = clazz;
        }

        public Class<?> getValue() {
            return clazz;
        }
    }

    private MatchType matchType = null;
    private Object matchValue = null;

    private Class<?> propertyClass = null;
    private String[] propertyNames = null;

    /**
     * default 构造函数
     */
    public PropertyFilter() {
    }

    /**
     * 构造函数
     *
     * @param filterName 比较属性字符串,含待比较的比较类型、属性值类型及属性列表.
     *                   eg. LIKES_NAME_OR_LOGIN_NAME
     * @param value      待比较的值.
     */
    public PropertyFilter(final String filterName, final String value) {

        String firstPart = StringUtils.substringBefore(filterName, "_");//likeS
        String matchTypeCode = StringUtils.substring(firstPart, 0, firstPart.length() - 1);//like
        String propertyTypeCode = StringUtils.substring(firstPart, firstPart.length() - 1, firstPart.length());//S

        try {
            matchType = Enum.valueOf(MatchType.class, matchTypeCode);//like
        } catch (RuntimeException e) {
            throw new IllegalArgumentException("filter名称" + filterName + "没有按规则编写,无法得到属性比较类型.", e);
        }

        try {
            propertyClass = Enum.valueOf(PropertyType.class, propertyTypeCode).getValue();//string
        } catch (RuntimeException e) {
            throw new IllegalArgumentException("filter名称" + filterName + "没有按规则编写,无法得到属性值类型.", e);
        }

        String propertyNameStr = StringUtils.substringAfter(filterName, "_");//NAME_OR_LOGIN_NAME
        Assert.isTrue(StringUtils.isNotBlank(propertyNameStr), "filter名称" + filterName + "没有按规则编写,无法得到属性名称.");
        propertyNames = StringUtils.splitByWholeSeparator(propertyNameStr, PropertyFilter.OR_SEPARATOR);//name,login_name

        if (matchType.equals(MatchType.IN)) {
            String[] values = value.split(",");
            this.matchValue = Arrays.asList((Object[]) ConvertUtils.convert(values, propertyClass));
        } else {
            this.matchValue = ConvertUtils.convert(value, propertyClass);
        }
    }

    /**
     * 从HttpRequest中创建PropertyFilter列表, 默认Filter属性名前缀为filter.
     *
     * @param request HttpServletRequest
     * @return List<PropertyFilter>
     * @see #buildFromHttpRequest(javax.servlet.http.HttpServletRequest, String)
     */
    public static List<PropertyFilter> buildFromHttpRequest(final HttpServletRequest request) {
        return buildFromHttpRequest(request, "filter");
    }

    /**
     * 从HttpRequest中创建PropertyFilter列表
     * PropertyFilter命名规则为Filter属性前缀_比较类型属性类型_属性名.
     * <p/>
     * eg.
     * filter_EQS_name
     * filter_LIKES_name_OR_email
     *
     * @param request      HttpServletRequest
     * @param filterPrefix 参数前增加的前缀
     * @return List<PropertyFilter>
     */
    public static List<PropertyFilter> buildFromHttpRequest(final HttpServletRequest request, final String filterPrefix) {
        List<PropertyFilter> filterList = new ArrayList<PropertyFilter>();

        //从request中获取含属性前缀名的参数,构造去除前缀名后的参数Map.
        Map<String, Object> filterParamMap = ServletUtils.getParametersStartingWith(request, filterPrefix + "_");

        //分析参数Map,构造PropertyFilter列表
        for (Map.Entry<String, Object> entry : filterParamMap.entrySet()) {
            String filterName = entry.getKey();
            String value = (String) entry.getValue();
            //如果value值为空,则忽略此filter.
            if (StringUtils.isNotBlank(value)) {
                PropertyFilter filter = new PropertyFilter(filterName, value);
                filterList.add(filter);
            }
        }

        return filterList;
    }

    /**
     * 获取比较值的类型.
     *
     * @return propertyClass
     */
    public Class<?> getPropertyClass() {
        return propertyClass;
    }

    /**
     * 获取比较方式.
     *
     * @return matchType
     */
    public MatchType getMatchType() {
        return matchType;
    }

    /**
     * 获取比较值.
     *
     * @return matchValue
     */
    public Object getMatchValue() {
        return matchValue;
    }

    /**
     * 获取比较属性名称列表.
     *
     * @return propertyNames
     */
    public String[] getPropertyNames() {
        return propertyNames;
    }

    /**
     * 获取唯一的比较属性名称.
     *
     * @return 返回propertyNames数组第一个属性名称
     */
    public String getPropertyName() {
        Assert.isTrue(propertyNames.length == 1, "There are not only one property in this filter.");
        return propertyNames[0];
    }

    /**
     * 是否比较多个属性.
     *
     * @return true：多个属性，false：1个属性
     */
    public boolean hasMultiProperties() {
        return (propertyNames.length > 1);
    }

    public static String getOperator(MatchType matchType) {
        String operator = "";
        //根据MatchType构造criterion
        switch (matchType) {
            case EQ:
                operator = "=";
                break;
            case NEQ:
                operator = "!=";
                break;
            case LIKE:
                operator = "like";
                break;
            case LE:
                operator = "<=";
                break;
            case LT:
                operator = "<";
                break;
            case GE:
                operator = ">=";
                break;
            case GT:
                operator = ">";
                break;
            case IN:
                operator = " in ";
        }
        return operator;
    }
}
